﻿namespace EFS.DB.Parameters
{
	public class Array
	{
		#region Composition

		/// <summary>
		/// Array
		/// </summary>
		private System.Data.SqlClient.SqlParameter[] sqlParametersArray = null;

		/// <summary>
		/// Keep dictionarry for output
		/// </summary>
		private System.Collections.Generic.Dictionary<System.String, System.Data.SqlClient.SqlParameter> outSqlParametersDictionary =
			new System.Collections.Generic.Dictionary<System.String, System.Data.SqlClient.SqlParameter>();

		#endregion

		/// <summary>
		/// MAKE sql parameters from names / values array, paramter directions is input
		/// </summary>
		/// <param name="names"></param>
		/// <param name="values"></param>
		/// <returns></returns>
		public Array(
			System.String[] names,
			System.Object[] values)
		{
			// check
			EFS.Common.Verify.Reference(names, "names");
			EFS.Common.Verify.Reference(values, "values");

			// must have same length
			if (names.Length != values.Length)
			{
				throw new System.ArgumentException("Names and Values array must have same length");
			}

			// create
			sqlParametersArray = new System.Data.SqlClient.SqlParameter[names.Length];

			// add sql parameters
			for (System.Int32 index = 0; null != names && index < names.Length; index++)
			{
				sqlParametersArray[index] = EFS.DB.Parameters.Parameter.Get(names[index], values[index]);
			}
		}

		/// <summary>
		/// MAKE sql parameters from names / values / direction array
		/// </summary>
		/// <param name="names"></param>
		/// <param name="values"></param>
		/// <returns></returns>
		public Array(
			System.String[] names,
			System.Object[] values,
			System.Boolean[] directionOut)
		{
			// check
			EFS.Common.Verify.Reference(names, "names");
			EFS.Common.Verify.Reference(values, "values");
			EFS.Common.Verify.Reference(directionOut, "directionOut");

			// must have same length
			if (names.Length != values.Length || names.Length != directionOut.Length)
			{
				throw new System.ArgumentException("Names and Values array must have same length");
			}

			// create
			sqlParametersArray = new System.Data.SqlClient.SqlParameter[names.Length];

			// add sql parameters
			for (System.Int32 index = 0; null != names && index < names.Length; index++)
			{
				// make sql parameter
				System.Data.SqlClient.SqlParameter sqlParameter = EFS.DB.Parameters.Parameter.Get(names[index], values[index]);

				// set direction
				sqlParameter.Direction = directionOut[index] ? System.Data.ParameterDirection.Output : System.Data.ParameterDirection.Input;

				// add to array
				sqlParametersArray[index] = sqlParameter;

				// add to output
				if (sqlParameter.Direction == System.Data.ParameterDirection.Output)
				{
					outSqlParametersDictionary.Add(sqlParameter.ParameterName, sqlParameter);
				}
			}
		}

		/// <summary>
		/// MAKE sql parameters from names / values / direction array
		/// </summary>
		/// <param name="names"></param>
		/// <param name="values"></param>
		/// <returns></returns>
		public Array(
			System.String[] names,
			System.Object[] values,
			System.Int32?[] sizes,
			System.Boolean[] directionOut)
		{
			// check
			EFS.Common.Verify.Reference(names, "names");
			EFS.Common.Verify.Reference(values, "values");
			EFS.Common.Verify.Reference(sizes, "sizes");
			EFS.Common.Verify.Reference(directionOut, "directionOut");

			// must have same length
			if (names.Length != directionOut.Length || values.Length != directionOut.Length || sizes.Length != directionOut.Length)
			{
				throw new System.ArgumentException("Names and Values array must have same length");
			}

			// create
			sqlParametersArray = new System.Data.SqlClient.SqlParameter[names.Length];

			// add sql parameters
			for (System.Int32 index = 0; null != names && index < names.Length; index++)
			{
				// make sql parameter
				System.Data.SqlClient.SqlParameter sqlParameter = EFS.DB.Parameters.Parameter.Get(names[index], values[index]);

				// set direction
				sqlParameter.Direction = directionOut[index] ? System.Data.ParameterDirection.Output : System.Data.ParameterDirection.Input;
				
				// size
				System.Int32? size = null;
				if (null != (size = sizes[index]))
 				{
					sqlParameter.Size = size.Value;
				}

				// add to array
				sqlParametersArray[index] = sqlParameter;

				// add to output
				if (sqlParameter.Direction == System.Data.ParameterDirection.Output)
				{
					outSqlParametersDictionary.Add(sqlParameter.ParameterName, sqlParameter);
				}
			}
		}

		/// <summary>
		/// Make SQL parameters array with one parameter
		/// </summary>
		/// <param name="dbName"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public Array(
			System.String dbName,
			System.Object value)
		{
			sqlParametersArray = new System.Data.SqlClient.SqlParameter[]
				{
					new System.Data.SqlClient.SqlParameter(dbName, value) 
				};
		}

		/// <summary>
		/// Get out value
		/// </summary>
		/// <param name="name"></param>
		/// <returns></returns>
		public ParameterType GetOutPrameterValue<ParameterType>(System.String name)
		{
			// check
			EFS.Common.Verify.String(name, "name");

			// check parameter
			if (!outSqlParametersDictionary.ContainsKey(name))
			{
				throw new System.ArgumentException("Parameter not found");
			}

			// get param
			System.Data.SqlClient.SqlParameter sqlParameter = outSqlParametersDictionary[name];

			// check
			if (null == sqlParameter.Value)
			{
				return default(ParameterType);
			}

			// check type
			if (!typeof(ParameterType).IsAssignableFrom(sqlParameter.Value.GetType()))
			{
				throw new System.InvalidOperationException("Parameter type missmatch");
			}

			// none
			return (ParameterType)sqlParameter.Value;
		}

		/// <summary>
		/// Get SQL parameters
		/// </summary>
		internal System.Data.SqlClient.SqlParameter[] SQLParametersArray
		{
			get { return sqlParametersArray; }
		}
	}
}